import 'dart:async';

import 'package:async/async.dart';
import 'package:async_test/src/utils.dart';

import '../common/test_page.dart';

class RejectErrorsTestPage extends TestPage {
  RejectErrorsTestPage(super.title) {
    late StreamController controller;
    setUp() {
      controller = StreamController();
    }

    test('StreamController().sink.rejectErrors()传递数据事件', () {
      setUp();
      controller.sink.rejectErrors()
        ..add(1)
        ..add(2)
        ..add(3);
      expect(controller.stream);
    });

    test('通过近距离活动', () {
      setUp();
      controller.sink.rejectErrors()
        ..add(1)
        ..close();
      expect(controller.stream);
    });

    test('通过addStream()中的数据事件', () {
      setUp();
      controller.sink.rejectErrors().addStream(Stream.fromIterable([1, 2, 3]));
      expect(controller.stream);
    });

    test('允许多个addStream()调用', () async {
      setUp();
      var transformed = controller.sink.rejectErrors();
      await transformed.addStream(Stream.fromIterable([1, 2, 3]));
      await transformed.addStream(Stream.fromIterable([4, 5, 6]));
      expect(controller.stream);
    });

    group('StreamController().sink.rejectErrors().addError()', () {
      test('转发要完成的错误', () {
        setUp();
        var transformed = controller.sink.rejectErrors();
        transformed.addError('oh no');
        expect(transformed.done);
      });

      test('关闭底层水槽', () {
        setUp();
        var transformed = controller.sink.rejectErrors();
        transformed.addError('oh no');
        transformed.done.catchError((_) {});

        expect(controller.stream);
      });

      test('忽略其他事件', () async {
        setUp();
        var transformed = controller.sink.rejectErrors();
        transformed.addError('oh no');
        transformed.done.catchError((_) {});
        expect(controller.stream);

        transformed
          ..add(1)
          ..addError('another');
        await pumpEventQueue();
        transformed
          ..add(2)
          ..addError('yet another');
      });

      test('取消当前订阅', () async {
        setUp();
        var inputCanceled = false;
        var inputController = StreamController(onCancel: () => inputCanceled = true);

        var transformed = controller.sink.rejectErrors()
          ..addStream(inputController.stream);
        inputController.addError('oh no');
        transformed.done.catchError((_) {});

        await pumpEventQueue();
        expect(inputCanceled);
      });
    });

    group('NullStreamSink(done: Completer().future).rejectErrors()当内部水槽完成以后', () {
      test('已完成', () async {
        setUp();
        var completer = Completer();
        var transformed = NullStreamSink(done: completer.future).rejectErrors();

        var doneCompleted = false;
        transformed.done.then((_) => doneCompleted = true);
        await pumpEventQueue();
        expect(doneCompleted);

        completer.complete();
        await pumpEventQueue();
        expect(doneCompleted);
      });

      test('一个未完成的addStream()完成', () async {
        setUp();
        var completer = Completer();
        var transformed = NullStreamSink(done: completer.future).rejectErrors();

        var addStreamCompleted = false;
        transformed
            .addStream(StreamController().stream)
            .then((_) => addStreamCompleted = true);
        await pumpEventQueue();
        expect(addStreamCompleted);

        completer.complete();
        await pumpEventQueue();
        expect(addStreamCompleted);
      });

      test('未完成的addStream()的订阅被取消', () async {
        setUp();
        var completer = Completer();
        var transformed = NullStreamSink(done: completer.future).rejectErrors();

        var addStreamCancelled = false;
        transformed.addStream(
            StreamController(onCancel: () => addStreamCancelled = true).stream);
        await pumpEventQueue();
        expect(addStreamCancelled);

        completer.complete();
        await pumpEventQueue();
        expect(addStreamCancelled);
      });

      test('转发一个未完成的addStream()的取消错误', () async {
        setUp();
        var completer = Completer();
        var transformed = NullStreamSink(done: completer.future).rejectErrors();

        expect(
            transformed.addStream(StreamController(onCancel: () => throw 'oh no').stream));
        completer.complete();
      });

      group('NullStreamSink(done: Future.error("oh no")).rejectErrors()', () {
        test('通过 完成', () async {
          expect(NullStreamSink(done: Future.error('oh no')).rejectErrors().done);
        });

        test('通过 关闭', () async {
          expect(NullStreamSink(done: Future.error('oh no')).rejectErrors().close());
        });
      });
    });

    group('关闭后', () {
      test('在add()上引发', () {
        setUp();
        var sink = controller.sink.rejectErrors()..close();
        expect(() => sink.add(1));
      });

      test('在addError()上引发', () {
        setUp();
        var sink = controller.sink.rejectErrors()..close();
        expect(() => sink.addError('oh no'));
      });

      test('在addStream()上引发', () {
        setUp();
        var sink = controller.sink.rejectErrors()..close();
        expect(() => sink.addStream(Stream.empty()));
      });

      test('允许关闭', () {
        setUp();
        var sink = controller.sink.rejectErrors()..close();
        sink.close();
        expect(sink.done);
      });
    });

    group('在活动addStream()期间', () {
      test('在add()上引发', () {
        setUp();
        var sink = controller.sink.rejectErrors()
          ..addStream(StreamController().stream);
        expect(() => sink.add(1));
      });

      test('在addError()上引发', () {
        var sink = controller.sink.rejectErrors()
          ..addStream(StreamController().stream);
        expect(() => sink.addError('oh no'));
      });

      test('在addStream()上引发', () {
        var sink = controller.sink.rejectErrors()
          ..addStream(StreamController().stream);
        expect(() => sink.addStream(Stream.empty()));
      });

      test('闭合时抛出()', () {
        var sink = controller.sink.rejectErrors()
          ..addStream(StreamController().stream);
        expect(() => sink.close());
      });
    });
  }

}